home *** CD-ROM | disk | FTP | other *** search
/ Languguage OS 2 / Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO / gnu / libg_261.zip / libg_261 / libg++ / src / RNG.cc < prev    next >
C/C++ Source or Header  |  1994-07-01  |  4KB  |  132 lines

  1. // This may look like C code, but it is really -*- C++ -*-
  2. /* 
  3. Copyright (C) 1989 Free Software Foundation
  4.  
  5. This file is part of the GNU C++ Library.  This library is free
  6. software; you can redistribute it and/or modify it under the terms of
  7. the GNU Library General Public License as published by the Free
  8. Software Foundation; either version 2 of the License, or (at your
  9. option) any later version.  This library is distributed in the hope
  10. that it will be useful, but WITHOUT ANY WARRANTY; without even the
  11. implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  12. PURPOSE.  See the GNU Library General Public License for more details.
  13. You should have received a copy of the GNU Library General Public
  14. License along with this library; if not, write to the Free Software
  15. Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  16. */
  17. #ifdef __GNUG__
  18. #pragma implementation
  19. #endif
  20. #include <assert.h>
  21. #include <builtin.h>
  22. #include <RNG.h>
  23.  
  24. // These two static fields get initialized by RNG::RNG().
  25. PrivateRNGSingleType RNG::singleMantissa;
  26. PrivateRNGDoubleType RNG::doubleMantissa;
  27.  
  28. //
  29. //    The scale constant is 2^-31. It is used to scale a 31 bit
  30. //    long to a double.
  31. //
  32.  
  33. //static const double randomDoubleScaleConstant = 4.656612873077392578125e-10;
  34. //static const float  randomFloatScaleConstant = 4.656612873077392578125e-10;
  35.  
  36. static char initialized = 0;
  37.  
  38. RNG::RNG()
  39. {
  40.   if (!initialized)
  41.   {
  42.  
  43.     assert (sizeof(double) == 2 * sizeof(_G_uint32_t)); 
  44.  
  45.     //
  46.     //    The following is a hack that I attribute to
  47.     //    Andres Nowatzyk at CMU. The intent of the loop
  48.     //    is to form the smallest number 0 <= x < 1.0,
  49.     //    which is then used as a mask for two longwords.
  50.     //    this gives us a fast way way to produce double
  51.     //    precision numbers from longwords.
  52.     //
  53.     //    I know that this works for IEEE and VAX floating
  54.     //    point representations.
  55.     //
  56.     //    A further complication is that gnu C will blow
  57.     //    the following loop, unless compiled with -ffloat-store,
  58.     //    because it uses extended representations for some of
  59.     //    of the comparisons. Thus, we have the following hack.
  60.     //    If we could specify #pragma optimize, we wouldn't need this.
  61.     //
  62.  
  63.     PrivateRNGDoubleType t;
  64.     PrivateRNGSingleType s;
  65.  
  66. #if _IEEE == 1
  67.     
  68.     t.d = 1.5;
  69.     if ( t.u[1] == 0 ) {        // sun word order?
  70.         t.u[0] = 0x3fffffff;
  71.         t.u[1] = 0xffffffff;
  72.     }
  73.     else {
  74.         t.u[0] = 0xffffffff;    // encore word order?
  75.         t.u[1] = 0x3fffffff;
  76.     }
  77.  
  78.     s.u = 0x3fffffff;
  79. #else
  80.     volatile double x = 1.0; // volatile needed when fp hardware used,
  81.                              // and has greater precision than memory doubles
  82.     double y = 0.5;
  83.     do {                // find largest fp-number < 2.0
  84.         t.d = x;
  85.         x += y;
  86.         y *= 0.5;
  87.     } while (x != t.d && x < 2.0);
  88.  
  89.     volatile float xx = 1.0; // volatile needed when fp hardware used,
  90.                              // and has greater precision than memory floats
  91.     float yy = 0.5;
  92.     do {                // find largest fp-number < 2.0
  93.         s.s = xx;
  94.         xx += yy;
  95.         yy *= 0.5;
  96.     } while (xx != s.s && xx < 2.0);
  97. #endif
  98.     // set doubleMantissa to 1 for each doubleMantissa bit
  99.     doubleMantissa.d = 1.0;
  100.     doubleMantissa.u[0] ^= t.u[0];
  101.     doubleMantissa.u[1] ^= t.u[1];
  102.  
  103.     // set singleMantissa to 1 for each singleMantissa bit
  104.     singleMantissa.s = 1.0;
  105.     singleMantissa.u ^= s.u;
  106.  
  107.     initialized = 1;
  108.     }
  109. }
  110.  
  111. float RNG::asFloat()
  112. {
  113.     PrivateRNGSingleType result;
  114.     result.s = 1.0;
  115.     result.u |= (asLong() & singleMantissa.u);
  116.     result.s -= 1.0;
  117.     assert( result.s < 1.0 && result.s >= 0);
  118.     return( result.s );
  119. }
  120.     
  121. double RNG::asDouble()
  122. {
  123.     PrivateRNGDoubleType result;
  124.     result.d = 1.0;
  125.     result.u[0] |= (asLong() & doubleMantissa.u[0]);
  126.     result.u[1] |= (asLong() & doubleMantissa.u[1]);
  127.     result.d -= 1.0;
  128.     assert( result.d < 1.0 && result.d >= 0);
  129.     return( result.d );
  130. }
  131.  
  132.